﻿using HslCommunication;
using HslCommunication.Core;
using HslCommunication.Core.Pipe;
using HslCommunication.ModBus;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace NewDevice.RS485
{
    /// <summary>
    /// pqw 继电器
    /// </summary>
    public class PQW_IO_V2
    {
        private SerialBase_V2 _sb;
        private readonly ModbusRtu _modbusRtu;// http://www.hsltechnology.cn:7900/Doc/HslCommunication

        /// <summary>
        /// ctor
        /// </summary>
        /// <param name="station"></param>
        /// <param name="pipe"></param>
        /// <param name="diChannelCount"></param>
        /// <param name="doChannelCount"></param>
        public PQW_IO_V2(byte station, SerialBase_V2 pipe, int diChannelCount, int doChannelCount)
        {
            _sb = pipe;
            _modbusRtu = new ModbusRtu();
            _modbusRtu.Station = station;
            _modbusRtu.DataFormat = DataFormat.ABCD;
            _modbusRtu.IsClearCacheBeforeRead = false;
            _modbusRtu.CommunicationPipe = pipe;

            _diChannelCount = (ushort)diChannelCount;
            _doChannelCount = (ushort)doChannelCount;
            _diStatus = new LockFreeBoolArray(diChannelCount);
            _doStatus = new LockFreeBoolArray(doChannelCount);
        }

        private ushort _diChannelCount = 16;
        private ushort _doChannelCount = 16;

        /// <summary>
        /// 输入状态
        /// </summary>
        private LockFreeBoolArray _diStatus;

        /// <summary>
        /// 输出状态
        /// </summary>
        private LockFreeBoolArray _doStatus;

        /// <summary>
        /// 设备描述
        /// </summary>
        public string DeviceDescription { get; set; } = "IO控制卡";

        /// <summary>
        /// 读取DI
        /// </summary>
        /// <param name="channel"></param>
        /// <returns></returns>
        public bool GetDi(int channel)
        {
            return _diStatus.GetValue(channel);
        }

        /// <summary>
        /// 读取DO
        /// </summary>
        /// <param name="channel"></param>
        /// <returns></returns>
        public bool GetDo(int channel)
        {
            return _doStatus.GetValue(channel);
        }

        /// <summary>
        /// 读取所有通道输入
        /// </summary>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public void ReadDiStatus()
        {
            try
            {
                OperateResult<bool[]> readResult;
                lock (_sb.Locker)
                {
                    readResult = _modbusRtu.ReadBool("x=2;0", _diChannelCount);
                    Thread.Sleep(_sb.Delay);
                }

                if (!readResult.IsSuccess)
                {
                    throw new Exception($"读取数据失败: {readResult.Message}");
                }
                for (int i = 0; i < _diChannelCount; i++)
                {
                    var rawValue = readResult.Content[i];

                    _diStatus.SetValue(i, rawValue);
                }
            }
            catch (Exception ex)
            {
                throw new Exception($"{DeviceDescription}读取所有通道数据时发生错误: {ex.Message}");
            }
        }

        /// <summary>
        /// 读取所有通道输入
        /// </summary>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public void ReadDoStatus()
        {
            try
            {
                // 假设每个通道占用2个寄存器，读取所有通道的数据
                OperateResult<bool[]> readResult;
                lock (_sb.Locker)
                {
                    readResult = _modbusRtu.ReadBool("x=1;0", _doChannelCount);
                    Thread.Sleep(_sb.Delay);
                }

                if (!readResult.IsSuccess)
                {
                    throw new Exception($"读取数据失败: {readResult.Message}");
                }
                for (int i = 0; i < _doChannelCount; i++)
                {
                    // 每个通道的数据由两个寄存器组成

                    var rawValue = readResult.Content[i];

                    _doStatus.SetValue(i, rawValue);
                }
            }
            catch (Exception ex)
            {
                throw new Exception($"{DeviceDescription}读取所有通道数据时发生错误: {ex.Message}");
            }
        }

        /// <summary>
        /// 设置单个通道的状态
        /// </summary>
        /// <param name="channel"></param>
        /// <param name="status"></param>
        /// <exception cref="Exception"></exception>
        public void WriteDo(int channel, bool status)
        {
            OperateResult writeResult;
            lock (_sb.Locker)
            {
                writeResult = _modbusRtu.Write($"x=05;{channel}", status);
                Thread.Sleep(_sb.Delay);
            }

            if (!writeResult.IsSuccess)
            {
                throw new Exception($"{DeviceDescription}(关闭单通道)写入数据失败: {writeResult.Message}");
            }
            ReadDoStatus();
            if (_doStatus.GetValue(channel) != status)
            {
                throw new Exception($"{DeviceDescription}设置输出通道回读不一致ch={channel}value={status}: {writeResult.Message}");
            }
        }

        /// <summary>
        /// 关闭所有通道
        /// </summary>
        /// <exception cref="Exception"></exception>
        public void OffAllChannels()
        {
            var writeResult = _modbusRtu.Write($"{0x85}", (short)0x0000);

            if (!writeResult.IsSuccess)
            {
                throw new Exception($"{DeviceDescription}(关闭所有通道)写入数据失败: {writeResult.Message}");
            }
            ReadDoStatus();
            for (int i = 0; i < _doChannelCount; i++)
            {
                if (_doStatus.GetValue(i))
                {
                    throw new Exception($"{DeviceDescription}(关闭所有通道)失败(回读指示有通道未关闭): {writeResult.Message}");
                }
            }
        }
    }
}